package com.example.demo.service.impl;

import com.example.demo.dto.ApiResponse;
import com.example.demo.entity.Lab;
import com.example.demo.entity.Reservation;
import com.example.demo.entity.ReservationStatus;
import com.example.demo.entity.TimeSlot;
import com.example.demo.repository.LabRepository;
import com.example.demo.repository.ReservationRepository;
import com.example.demo.repository.TimeSlotRepository;
import com.example.demo.service.LabService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
@RequiredArgsConstructor
public class LabServiceImpl implements LabService {

    private final LabRepository labRepository;
    private final ReservationRepository reservationRepository;
    private final TimeSlotRepository timeSlotRepository;

    @Override
    public ApiResponse<?> getAvailableLabs(String date, String timeSlot) {
        try {
            // 解析日期和时间段
            LocalDate localDate = date != null ? LocalDate.parse(date) : LocalDate.now();
            LocalTime startTime = timeSlot != null ? LocalTime.parse(timeSlot) : LocalTime.now();
            LocalTime endTime = startTime.plusHours(2); // 默认时间段为2小时

            LocalDateTime startDateTime = LocalDateTime.of(localDate, startTime);
            LocalDateTime endDateTime = LocalDateTime.of(localDate, endTime);

            // 获取所有实验室
            List<Lab> allLabs = labRepository.findAll();

            // 获取在指定时间段内已被预约的实验室
            List<Reservation> existingReservations = reservationRepository.findByStartTimeBetween(
                startDateTime, endDateTime);

            // 过滤出未被预约的实验室
            List<Lab> availableLabs = allLabs.stream()
                .filter(lab -> existingReservations.stream()
                    .noneMatch(reservation -> 
                        reservation.getLab().getId().equals(lab.getId()) &&
                        reservation.getStatus() == ReservationStatus.APPROVED))
                .collect(Collectors.toList());

            // 为每个实验室添加可预约时间段信息
            availableLabs.forEach(lab -> {
                // 获取该实验室的所有可用时间段
                List<TimeSlot> availableTimeSlots = lab.getAvailableTimeSlots();
                
                // 过滤掉已被预约的时间段
                List<TimeSlot> trulyAvailableTimeSlots = availableTimeSlots.stream()
                    .filter(slot -> existingReservations.stream()
                        .noneMatch(reservation -> 
                            reservation.getLab().getId().equals(lab.getId()) &&
                            reservation.getStartTime().toLocalTime().equals(slot.getStartTime()) &&
                            reservation.getStatus() == ReservationStatus.APPROVED))
                    .collect(Collectors.toList());
                
                lab.setAvailableTimeSlots(trulyAvailableTimeSlots);
            });

            return ApiResponse.success("获取可预约实验室成功", availableLabs);
        } catch (Exception e) {
            return ApiResponse.error("获取可预约实验室失败：" + e.getMessage());
        }
    }

    @Override
    public ApiResponse<?> createLab(Lab lab) {
        try {
            // 保存实验室基本信息
            final Lab savedLab = labRepository.save(lab);
            
            // 如果提供了时间段，则添加时间段
            if (lab.getAvailableTimeSlots() != null && !lab.getAvailableTimeSlots().isEmpty()) {
                // 设置每个时间段的实验室引用
                lab.getAvailableTimeSlots().forEach(timeSlot -> {
                    timeSlot.setLab(savedLab);
                });
                
                // 保存所有时间段
                List<TimeSlot> savedTimeSlots = timeSlotRepository.saveAll(lab.getAvailableTimeSlots());
                savedLab.setAvailableTimeSlots(savedTimeSlots);
                
                // 保存更新后的实验室
                return ApiResponse.success("实验室创建成功", labRepository.save(savedLab));
            }
            
            return ApiResponse.success("实验室创建成功", savedLab);
        } catch (Exception e) {
            return ApiResponse.error("实验室创建失败：" + e.getMessage());
        }
    }

    @Override
    public ApiResponse<?> updateLab(Long id, Lab lab) {
        return labRepository.findById(id)
            .map(existingLab -> {
                // 更新实验室信息
                if (lab.getName() != null) existingLab.setName(lab.getName());
                if (lab.getLocation() != null) existingLab.setLocation(lab.getLocation());
                if (lab.getCapacity() != null) existingLab.setCapacity(lab.getCapacity());
                if (lab.getDescription() != null) existingLab.setDescription(lab.getDescription());
                if (lab.getCategory() != null) existingLab.setCategory(lab.getCategory());
                if (lab.getAvailableTimeSlots() != null) existingLab.setAvailableTimeSlots(lab.getAvailableTimeSlots());
                
                return ApiResponse.success("实验室信息更新成功", labRepository.save(existingLab));
            })
            .orElse(ApiResponse.error("实验室不存在"));
    }

    @Override
    public ApiResponse<?> deleteLab(Long id) {
        try {
            labRepository.deleteById(id);
            return ApiResponse.success("实验室删除成功");
        } catch (Exception e) {
            return ApiResponse.error("实验室删除失败：" + e.getMessage());
        }
    }

    @Override
    public ApiResponse<?> getLabById(Long id) {
        return labRepository.findById(id)
            .map(ApiResponse::success)
            .orElse(ApiResponse.error("实验室不存在"));
    }

    @Override
    public ApiResponse<?> getAllLabs() {
        try {
            List<Lab> labs = labRepository.findAll();
            // 为每个实验室添加可预约时间段信息
            labs.forEach(lab -> {
                List<TimeSlot> availableTimeSlots = lab.getAvailableTimeSlots();
                lab.setAvailableTimeSlots(availableTimeSlots);
            });
            return ApiResponse.success(labs);
        } catch (Exception e) {
            return ApiResponse.error("获取实验室列表失败：" + e.getMessage());
        }
    }

    @Override
    public ApiResponse<?> getLabsByCategory(Long categoryId) {
        try {
            List<Lab> labs = labRepository.findByCategoryId(categoryId);
            // 为每个实验室添加可预约时间段信息
            labs.forEach(lab -> {
                List<TimeSlot> availableTimeSlots = lab.getAvailableTimeSlots();
                lab.setAvailableTimeSlots(availableTimeSlots);
            });
            return ApiResponse.success(labs);
        } catch (Exception e) {
            return ApiResponse.error("获取分类实验室失败：" + e.getMessage());
        }
    }

    @Override
    public ApiResponse<?> addImage(Long id, String imageUrl) {
        return labRepository.findById(id)
            .map(lab -> {
                lab.getImages().add(imageUrl);
                return ApiResponse.success("图片添加成功", labRepository.save(lab));
            })
            .orElse(ApiResponse.error("实验室不存在"));
    }

    @Override
    public ApiResponse<?> removeImage(Long id, String imageUrl) {
        return labRepository.findById(id)
            .map(lab -> {
                lab.getImages().remove(imageUrl);
                return ApiResponse.success("图片删除成功", labRepository.save(lab));
            })
            .orElse(ApiResponse.error("实验室不存在"));
    }

    @Override
    public ApiResponse<?> addTimeSlot(Long labId, TimeSlot timeSlot) {
        return labRepository.findById(labId)
            .map(lab -> {
                // 检查时间段是否已存在
                boolean timeSlotExists = lab.getAvailableTimeSlots().stream()
                    .anyMatch(existingSlot -> 
                        existingSlot.getStartTime().equals(timeSlot.getStartTime()) &&
                        existingSlot.getEndTime().equals(timeSlot.getEndTime()));
                
                if (timeSlotExists) {
                    return ApiResponse.error("该时间段已存在");
                }

                // 设置默认值
                timeSlot.setIsAvailable(true);
                timeSlot.setLab(lab);
                
                // 保存时间段
                TimeSlot savedTimeSlot = timeSlotRepository.save(timeSlot);
                
                // 添加到实验室的时间段列表
                lab.getAvailableTimeSlots().add(savedTimeSlot);
                
                // 保存更新后的实验室
                labRepository.save(lab);
                
                return ApiResponse.success("时间段添加成功", savedTimeSlot);
            })
            .orElse(ApiResponse.error("实验室不存在"));
    }

    @Override
    public ApiResponse<?> removeTimeSlot(Long labId, Long timeSlotId) {
        return labRepository.findById(labId)
            .map(lab -> {
                boolean removed = lab.getAvailableTimeSlots().removeIf(slot -> slot.getId().equals(timeSlotId));
                if (removed) {
                    labRepository.save(lab);
                    timeSlotRepository.deleteById(timeSlotId);
                    return ApiResponse.success("时间段删除成功");
                }
                return ApiResponse.error("时间段不存在");
            })
            .orElse(ApiResponse.error("实验室不存在"));
    }

    @Override
    public ApiResponse<?> updateTimeSlot(Long labId, Long timeSlotId, TimeSlot timeSlot) {
        return labRepository.findById(labId)
            .map(lab -> {
                return lab.getAvailableTimeSlots().stream()
                    .filter(slot -> slot.getId().equals(timeSlotId))
                    .findFirst()
                    .map(existingSlot -> {
                        // 更新时间段信息
                        if (timeSlot.getStartTime() != null) existingSlot.setStartTime(timeSlot.getStartTime());
                        if (timeSlot.getEndTime() != null) existingSlot.setEndTime(timeSlot.getEndTime());
                        if (timeSlot.getName() != null) existingSlot.setName(timeSlot.getName());
                        if (timeSlot.getOrderNum() != null) existingSlot.setOrderNum(timeSlot.getOrderNum());
                        
                        TimeSlot updatedSlot = timeSlotRepository.save(existingSlot);
                        return ApiResponse.success("时间段更新成功", updatedSlot);
                    })
                    .orElse(ApiResponse.error("时间段不存在"));
            })
            .orElse(ApiResponse.error("实验室不存在"));
    }

    @Override
    public ApiResponse<?> getTimeSlots(Long labId) {
        return labRepository.findById(labId)
            .map(lab -> ApiResponse.success(timeSlotRepository.findByLabIdOrderByOrderNumAsc(labId)))
            .orElse(ApiResponse.error("实验室不存在"));
    }
} 